import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:densefog/block_item.dart';
import 'package:densefog/block_item_widget.dart';
import 'package:densefog/board_cell_painter.dart';
import 'package:densefog/const.dart';
import 'package:densefog/level_manager.dart';
import 'package:densefog/theme_provider.dart';
import 'package:densefog/themes.dart';
import 'package:densefog/utils.dart';

void main() {
  Paint.enableDithering = true;

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: '谜雾之路',
      theme: ThemeData(
        fontFamily: 'kuail',
        primarySwatch: Colors.grey,
      ),
      home: const Scaffold(
        body: Puzzle(),
      ),
    );
  }
}

class Puzzle extends StatefulWidget {
  const Puzzle({Key? key}) : super(key: key);

  @override
  State<Puzzle> createState() => _PuzzleState();
}

class _PuzzleState extends State<Puzzle> {
  var mainRect = const Rect.fromLTWH(0, 0, boardWidth, boardHeight);

  late List<ValueNotifier<BlockItem>> _positions;

  final ValueNotifier<int> _stepCounter = ValueNotifier<int>(0);

  int _position = 0;

  final themeController = ThemeController.init();

  late PuzzleThemeData themeData;

  List<ValueNotifier<BlockItem>> _createPositions() {
    final _levelPositions = levelManager.getLevel(_position);

    return _levelPositions
        .mapIndexed((index, e) => ValueNotifier(_levelPositions[index]))
        .toList();
  }

  @override
  void initState() {
    super.initState();
    themeData = themeController.getThemeData();
    _positions = _createPositions();
  }

  bool _checkWin(int index) {
    final item = _positions[index].value;
    return item.isMainPosition && item.x == 1 && item.y == 3;
  }

  void _dragEnd(int index) {
    final newX = withPrecision4(_positions[index].value.rect.left / cellSize)
        .roundToDouble();
    final newY = withPrecision4(_positions[index].value.rect.top / cellSize)
        .roundToDouble();

    if (_onNewPosition(index, newX, newY)) {
      _stepCounter.value = _stepCounter.value + 1;
    }

    _positions[index].value = BlockItem.copy(
      _positions[index].value,
      x: newX,
      y: newY,
    );

    if (_checkWin(index)) {
      showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext context) {
          return AlertDialog(
            backgroundColor: themeData.bgGradient.colors.last,
            title: ConstrainedBox(
              constraints: BoxConstraints.tightForFinite(
                width: withPrecision4(boardWidth),
              ),
              child: Text(
                "太棒了！要不要开启下一关？",
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: themeData.textColor,
                ),
              ),
            ),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(25.0),
            ),
            content: ElevatedButton(
              style: ElevatedButton.styleFrom(
                primary: themeData.plainBlockGradient.colors.first,
                onPrimary: themeData.textColor,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(25.0),
                ),
              ),
              child: Text(
                "开启",
                style: TextStyle(color: themeData.textColor),
              ),
              onPressed: () {
                setState(() {
                  if (_position < levelManager.levelCount - 1) {
                    _position++;
                  } else {
                    _position = 0;
                  }

                  _positions = _createPositions();
                  _stepCounter.value = 0;
                });

                Navigator.of(context).pop();
              },
            ),
          );
        },
      );
    }
  }

  bool _onNewPosition(int index, double newX, double newY) {
    return _positions[index].value.x != newX ||
        _positions[index].value.y != newY;
  }

  void _onDrag(int index, Offset offset) {
    final newRect = Rect.fromLTWH(
      withPrecision4(_positions[index].value.rect.left + offset.dx),
      withPrecision4(_positions[index].value.rect.top + offset.dy),
      withPrecision4(_positions[index].value.rect.width),
      withPrecision4(_positions[index].value.rect.height),
    );

    if (insideMainRect(mainRect, newRect)) {
      final res = _positions
          .where((element) => element.value.id != _positions[index].value.id)
          .fold<Rect>(
        newRect,
        (previousValue, element) {
          return optPosition(
            _positions[index].value.rect,
            previousValue,
            element.value.rect,
          );
        },
      );

      final copied = BlockItem.copy(_positions[index].value);
      copied.rect = res;
      _positions[index].value = copied;
    }
  }

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        gradient: themeData.bgGradient,
      ),
      child: SafeArea(
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ConstrainedBox(
                constraints: BoxConstraints.tightForFinite(
                  width: withPrecision4(boardWidth),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(bottom: 4),
                      child: Text(
                        "第 ${_position + 1} 关",
                        style: TextStyle(
                          color: themeData.textColor,
                          fontSize: 39,
                        ),
                      ),
                    ),
                    ValueListenableBuilder<int>(
                      valueListenable: _stepCounter,
                      builder: (
                        BuildContext context,
                        int value,
                        Widget? child,
                      ) {
                        return Text(
                          "$value",
                          style: TextStyle(
                            fontWeight: FontWeight.normal,
                            fontSize: 48,
                            color: themeData.stepsColor,
                            shadows: const [
                              BoxShadow(
                                color: Colors.black54,
                                blurRadius: 3.0,
                                spreadRadius: -3.0,
                                offset: Offset(0, 2),
                              ),
                              BoxShadow(
                                color: Colors.white10,
                                blurRadius: 1.0,
                                spreadRadius: -3.0,
                                offset: Offset(0, -1),
                              ),
                            ],
                          ),
                        );
                      },
                    )
                  ],
                ),
              ),
              const SizedBox(
                height: 24,
              ),
              SizedBox(
                width: withPrecision4(boardWidth),
                height: withPrecision4(boardHeight),
                child: Stack(
                  fit: StackFit.expand,
                  children: [
                    Center(
                      child: RepaintBoundary(
                        child: CustomPaint(
                          isComplex: true,
                          willChange: false,
                          painter: BoardCellPainter(
                            fieldCellColor: themeData.borderDotsColor,
                            borderColor: themeData.borderColor,
                          ),
                          child: const Center(
                            child: SizedBox(),
                          ),
                        ),
                      ),
                    ),
                    for (var i = 0; i < _positions.length; i++)
                      ValueListenableBuilder<BlockItem>(
                        valueListenable: _positions[i],
                        builder: (BuildContext context, BlockItem item,
                            Widget? child) {
                          return Positioned.fromRect(
                            rect: item.rect,
                            child: GestureDetector(
                              onVerticalDragUpdate: (event) {
                                _onDrag(i, event.delta);
                              },
                              onHorizontalDragUpdate: (event) {
                                _onDrag(i, event.delta);
                              },
                              onHorizontalDragEnd: (_) {
                                _dragEnd(i);
                              },
                              onVerticalDragEnd: (_) {
                                _dragEnd(i);
                              },
                              child: Padding(
                                padding: const EdgeInsets.all(4.0),
                                child: BlockItemWidget(
                                  item: item,
                                  gradient: item.isMainPosition
                                      ? themeData.mainBlockGradient
                                      : themeData.plainBlockGradient,
                                ),
                              ),
                            ),
                          );
                        },
                      )
                  ],
                ),
              ),
              const SizedBox(
                height: 48,
              ),
              Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  GameButton(
                    icon: Icons.palette_outlined,
                    themeData: themeData,
                    onTap: () {
                      setState(() {
                        themeController.nextTheme();
                        themeData = themeController.getThemeData();
                      });
                    },
                  ),
                  const SizedBox(width: 16),
                  GameButton(
                    icon: Icons.refresh,
                    themeData: themeData,
                    onTap: () {
                      _stepCounter.value = 0;

                      setState(() {
                        _positions = _createPositions();
                      });
                    },
                  ),
                  const SizedBox(width: 16),
                  GameButton(
                    icon: Icons.help_outline,
                    themeData: themeData,
                    onTap: () {
                      showDialog(
                        context: context,
                        barrierDismissible: false,
                        builder: (BuildContext context) {
                          return AlertDialog(
                            backgroundColor: themeData.bgGradient.colors.last,
                            title: ConstrainedBox(
                              constraints: BoxConstraints.tightForFinite(
                                width: withPrecision4(boardWidth),
                              ),
                              child: Text(
                                "通过移动各个棋子，帮助大箭头方块从初始位置移到棋盘最下方，从出口逃走。\n\n注意：\n不允许跨越棋子，还要设法用最少的步数把大箭头方块移到出口。",
                                textAlign: TextAlign.left,
                                style: TextStyle(
                                  color: themeData.textColor,
                                ),
                              ),
                            ),
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(25.0),
                            ),
                            content: ElevatedButton(
                              style: ElevatedButton.styleFrom(
                                primary:
                                    themeData.plainBlockGradient.colors.first,
                                onPrimary: themeData.textColor,
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(25.0),
                                ),
                              ),
                              child: Text(
                                "我知道了",
                                style: TextStyle(color: themeData.textColor),
                              ),
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                            ),
                          );
                        },
                      );
                    },
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class GameButton extends StatelessWidget {
  final IconData icon;
  final VoidCallback onTap;
  final PuzzleThemeData themeData;

  const GameButton({
    Key? key,
    required this.icon,
    required this.onTap,
    required this.themeData,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,
      clipBehavior: Clip.antiAlias,
      borderRadius: const BorderRadius.all(Radius.circular(borderRadius)),
      child: Ink(
        decoration: BoxDecoration(
            shape: BoxShape.rectangle,
            borderRadius: const BorderRadius.all(Radius.circular(borderRadius)),
            color: themeData.buttonBgColor,
            border: Border.all(color: themeData.buttonBgColor.withOpacity(0.5)),
            boxShadow: const [
              BoxShadow(
                color: Colors.black26,
                blurRadius: 3.0,
                spreadRadius: -2.0,
                offset: Offset(0, 4),
              ),
            ]),
        child: InkWell(
          borderRadius: BorderRadius.circular(borderRadius),
          highlightColor: Colors.black26,
          splashColor: Colors.transparent,
          onTap: onTap,
          child: Padding(
            padding: const EdgeInsets.all(12.0),
            child: Icon(
              icon,
              color: themeData.buttonFgColor,
              size: 36,
            ),
          ),
        ),
      ),
    );
  }
}
